package fr.inserm.umr915.vcfannotator.annotators;

import java.io.BufferedReader;
import java.io.IOException;

import fr.inserm.umr915.libjson.ObjectNode;
import fr.inserm.umr915.vcfannotator.AnnotationException;
import fr.inserm.umr915.vcfannotator.Variant;
import fr.inserm.umr915.vcfannotator.io.IOUtils;


import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.SecondaryCursor;

public class PhastConsAnnotator extends AbstractAnnotator
	{
	private String build;
	private String base="http://hgdownload.cse.ucsc.edu/goldenPath/hg19/phastCons46way/vertebrate";
	private SecondaryCursor cursor=null;
	private DatabaseEntry key=new DatabaseEntry();
	private DatabaseEntry pKey=new DatabaseEntry();
	private DatabaseEntry data=new DatabaseEntry();
	private Variant.Binding variantBinding=new Variant.Binding();
	protected String currChrom=null;
	protected int currPosition=0;
	protected int currStep=1;
	protected int currSpan=1;

	public PhastConsAnnotator()
		{
		setName("PhasCons46 way");
		}
	
	public void setBuild(String build)
		{
		this.build = build;
		}
	
	public String getBuild()
		{
		return build;
		}
	
	public void setBase(String base)
		{
		this.base = base;
		}
	
	public String getBase()
		{
		return base;
		}
	public BufferedReader openWig(String chrom)
		throws IOException
		{
		String url=getBase()+"/"+chrom+".phastCons46way.wigFix.gz";
		LOG.info(url);
		BufferedReader r=IOUtils.openReader(url);
		return r;
		}
	
	protected OperationStatus fixedStep(String line)
		{
		LOG.info(line);
		currChrom=null;
		currPosition=0;
		currStep=1;
		currSpan=1;
		for(String s:line.split("[ ]+"))
			{
			int i=s.indexOf('=');
			if(i==-1) continue;
			if(s.startsWith("chrom="))
				{
				currChrom=s.substring(i+1);
				}
			else if(s.startsWith("start="))
				{
				currPosition=Integer.parseInt(s.substring(i+1));
				}
			else if(s.startsWith("step="))
				{
				currStep=Integer.parseInt(s.substring(i+1));
				}
			else if(s.startsWith("span="))
				{
				currSpan=Integer.parseInt(s.substring(i+1));
				}
			}
		Variant var=new Variant(
				getBuild(),
				this.currChrom,
				this.currPosition,
				"","");
		variantBinding.objectToEntry(var, key);
		return this.cursor.getSearchKeyRange(this.key,this.pKey,this.data, LockMode.DEFAULT);
		}

	
	@Override
	public void annotate() throws AnnotationException
		{
		BufferedReader r=null;
		try
			{
			this.cursor=super.baseDatabase.getVariantDatabase().openCursor(null, null);
			for(String chrom:baseDatabase.getChromosomes(getBuild()))
				{
				r=openWig(chrom);
				String line;
				int nLines=0;
				boolean afterFixedStep=true;
				while((line=r.readLine())!=null)
					{
					++nLines;
					if(nLines%1000000==0) LOG.info(line);
					if(line.startsWith("fixedStep"))
						{
						if(fixedStep(line)!=OperationStatus.SUCCESS) break;
						afterFixedStep=true;
						continue;
						}
					int rewindCount=0;
					for(;;)
						{
						if(!afterFixedStep)
							{
							if(this.cursor.getNext(this.key,this.pKey,this.data, LockMode.DEFAULT)!=OperationStatus.SUCCESS) break;
							}
						afterFixedStep=false;
						
						Variant var=variantBinding.entryToObject(key);
					
						//advance variation_index
						int i= var.getBuild().compareTo(this.getBuild());
						if(i< -1) continue;
						if(i>1) break;
						i= var.getChrom().compareTo(this.currChrom);
						if(i< -1) continue;
						if(i>1) break;
						if(var.getPosition()-1 < currPosition) continue;
						rewindCount++;
						if(var.getPosition()-1 >= currPosition+currStep) break;
						LOG.info(var.toString()+" "+line);
						ObjectNode annotation= nodeBinding.entryToObject(data).asObjectNode();
						annotation.put("phastCons46",nodeFactory.createFloatNode(Double.parseDouble(line)));
						nodeBinding.objectToEntry(annotation, data);
						if(baseDatabase.getJsonDatabase().put(null, pKey, data)!=OperationStatus.SUCCESS)
							{
							throw new RuntimeException("Cannot re-insert "+var+":"+annotation);
							}
						}
					for(int n=0;n< rewindCount;++n)
						{
						if(this.cursor.getPrev(this.key,this.pKey,this.data, LockMode.DEFAULT)!=OperationStatus.SUCCESS)
							{
							LOG.info("cannot rewing "+currChrom+":"+currPosition);
							break;
							//throw new AnnotationException("Cannot rewind");
							}
						}
					currPosition+=currStep;
					}
	
				r.close();
				r=null;
				}
			}
		catch(IOException err)
			{
			throw new AnnotationException(err);
			}
		finally
			{
			if(r!=null) try {r.close();} catch(IOException err) {}
			if(this.cursor!=null) this.cursor.close();
			this.cursor=null;
			}
		}
	
	
	
	}
